#ifndef THREAD_UTIL_H_
#define THREAD_UTIL_H_

#include "base/macro_def.h"
#include "base/scoped_ptr.h"

#include <pthread.h>

class Mutex {
 public:
  Mutex() {
    ::pthread_mutex_init(&mutex_, NULL);
  }
  ~Mutex() {
    ::pthread_mutex_destroy(&mutex_);
  }

  void Lock() {
    ::pthread_mutex_lock(&mutex_);
  }
  void UnLock() {
    ::pthread_mutex_unlock(&mutex_);
  }

  pthread_mutex_t* get() {
    return &mutex_;
  }

 private:
  pthread_mutex_t mutex_;

  DISALLOW_COPY_AND_ASSIGN (Mutex);
};

class ScopedMutex {
 public:
  ScopedMutex(Mutex* m)
      : m_(m) {
    m_->Lock();
  }
  ~ScopedMutex() {
    m_->UnLock();
  }

 private:
  Mutex* m_;

  DISALLOW_COPY_AND_ASSIGN(ScopedMutex);
};

class Rwlock {
 public:
  Rwlock() {
    ::pthread_rwlock_init(&rw_lock_, NULL);
  }
  ~Rwlock() {
    ::pthread_rwlock_destroy(&rw_lock_);
  }

  void ReadLock() {
    ::pthread_rwlock_rdlock(&rw_lock_);
  }
  void WriteLock() {
    ::pthread_rwlock_wrlock(&rw_lock_);
  }
  void UnLock() {
    ::pthread_rwlock_unlock(&rw_lock_);
  }

 private:
  pthread_rwlock_t rw_lock_;

  DISALLOW_COPY_AND_ASSIGN(Rwlock);
};

class ScopedReadLock {
 public:
  ScopedReadLock(Rwlock* rw_lock)
      : rw_lock_(rw_lock) {
    rw_lock_->ReadLock();
  }
  ~ScopedReadLock() {
    rw_lock_->UnLock();
  }

 private:
  Rwlock* rw_lock_;

  DISALLOW_COPY_AND_ASSIGN(ScopedReadLock);
};

class ScopedWriteLock {
 public:
  ScopedWriteLock(Rwlock* rw_lock)
      : rw_lock_(rw_lock) {
    rw_lock_->WriteLock();
  }
  ~ScopedWriteLock() {
    rw_lock_->UnLock();
  }

 private:
  Rwlock* rw_lock_;

  DISALLOW_COPY_AND_ASSIGN(ScopedWriteLock);
};

#endif
